"""
       @File     : pre4.py
       @IDE      : PyCharm
       @Author   : 陈引弟
       @Date     : 2025/3/13 15:19
       @Desc     :
=========================================================
"""
# 导入Python的数据处理库pandas，相当于python里的exceL
import pandas as pd

# 导入python绘图imatplotLib
import matplotlib
matplotlib.use('TkAgg')  # 在导入 pyplot 之前设置后端
import matplotlib.pyplot as plt

# 设置绘图大小
plt.style.use({'figure.figsize':(25,20)})
plt.rcParams['font.sans-serif']=['SimHei']   # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False   # 用来正常显示负号

# 调用pandas的read_csV函数读取数据集文件
df=pd.read_csv(r'F:\python\基于大数据的天气预测分析系统\model\weather.csv')
# 重新调用pandas的read_csV函数读取数据集文件
df2= pd.read_csv(r'F:\python\基于大数据的天气预测分析系统\model\weather.csv')

df2.head()
df2['Date']= pd.to_datetime(df2['Date'])
# 构造新的一列:年
df2.loc[:,'year']=df2['Date'].apply(lambda x:x.year)
# 构造新的一列:月
df2.loc[:,'month']= df2['Date'].apply(lambda x:x.month)
# 构诰新的一列，是期几 #构造新的一列:星期几
df2.loc[:,'dow']= df2['Date'].apply(lambda x:x.dayofweek)
# 构造新的一列:一个月第几天
df2. loc[:,'dom']= df2['Date'].apply(lambda x:x.day)
# 构造新的三列、是不是周末、是不是周六、是不是周日
df2.loc[:,'weekend']=df2['Date'].apply(lambda x:x.dayofweek>4)
df2.loc[:,'weekend_sat']=df2['Date'].apply(lambda x:x.dayofweek==5)
df2.loc[:,'weekend_sun']=df2['Date'].apply(lambda x:x.dayofweek==6)

df2.head( )

# 添加上半月和下半月的信息
def half_month(day):
    if day in range(1,16):
        return 1
    else:
        return 2
df2.loc[:,'half_month'] =df2['dom'].apply(lambda x:half_month(x))
# 添加每个月上中下旬的信息
def three_part_month(day):
    if day in range(1,11):
        return 1
    if day in range (11,21):
        return 2
    else:
        return 3
df2.loc[:, 'three_part_month']= df2['dom'].apply(lambda x:three_part_month(x))

# 添加每个月四下层期的信息
def four_week_month(day):
    if day in range(1,8):
        return 1
    if day in range(8,15):
        return 2
    if day in range (15,22):
        return 3
    else:
        return 4
df2.loc[:, 'four_week_month']= df2['dom'].apply(lambda x:four_week_month(x))

df2.head(35)

# 派加放假注信息
df2.loc[:,'festival']=0
df2.loc[(df2.month==1)&(df2.dom<4), 'festival']=1


before_dummy_df=df2.copy()


# 构造叫放据集的特征
drop_columns =['Date', 'Temp']
X_before_dummy = before_dummy_df.drop(drop_columns,axis=1)
X_before_dummy.head()



# 没置要进行独热向量编码的列
columns_to_encoding=['year','month','dow','dom','three_part_month','four_week_month']

# 使田pandas点get_net
dummy_df=pd.get_dummies(df2,columns=columns_to_encoding)


Y=dummy_df['Temp']
drop_columns =['Date','Temp']
X_dummy =dummy_df.drop(drop_columns,axis=1)

from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(X_dummy, Y,test_size=0.2, random_state=1,shuffle=True)

from sklearn import linear_model
from sklearn.neighbors import KNeighborsRegressor

lr_reg = linear_model.LinearRegression()
lr_reg.fit(x_train,y_train)
print('截距',lr_reg.intercept_)
print('斜率（线性模型中各特征对应的系数）',lr_reg.coef_)


df.loc[:,'线性回归']=lr_reg.predict(X_dummy)

knn_reg=KNeighborsRegressor()
knn_reg.fit(x_train,y_train)
df.loc[:,'KNN']=knn_reg.predict(X_dummy)


from sklearn.preprocessing import PolynomialFeatures

# 构建一个特征处理器
poly_reg = PolynomialFeatures(degree=2)

# 使用构建的·二次多项式处理特征
X_poly = poly_reg.fit_transform(X_dummy)

from sklearn import linear_model
lin_reg_2 = linear_model.LinearRegression()
lin_reg_2.fit(X_poly,Y)

df.loc[:,'二次多项式回归']=lin_reg_2.predict(X_poly)


from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(X_before_dummy,Y,test_size=0.2, random_state=1,shuffle=True)

# 从python 机器学习与数据挖掘工具库sklearn中导入随机森林回归器
from sklearn.ensemble import RandomForestRegressor

#
#
from sklearn.model_selection import GridSearchCV

#
param_grid = {
    'n_estimators':[5,10,20,50,100,200], # 决策树的个数
    'max_depth':[3,5,7],
    'max_features':[0.6,0.7,0.8,1]
}

# 实例化随机森林回归器
rf=RandomForestRegressor()

#
grid=GridSearchCV(rf,param_grid=param_grid,cv=3)

# 在训练集上训练
grid.fit(x_train,y_train)

# 查看效果最好的参数
print(grid.best_params_)

#
rf_reg=grid.best_estimator_

import numpy as np
print('特征排序：')
feature_names=['year','month','dow','dom','weekend','weekend_sat','weekend_sun',
               'half_month','three_part_month','four_week_month','festival']
feature_importances=rf_reg.feature_importances_
indices=np.argsort(feature_importances)[::-1]

for index in indices:
    print("feature %s (%f)" %(feature_names[index],feature_importances[index]))


plt.figure(figsize=(16,8))
plt.title("随机森林模型不同特征的重要度")
plt.bar(range(len(feature_importances)),feature_importances[indices],color='b')
plt.xticks(range(len(feature_importances)),np.array(feature_names)[indices],color='b')

df.loc[:,'随机森林']=rf_reg.predict(X_before_dummy)


#
fig,ax=plt.subplots(figsize=(30,25))

# 绘制气温散点图
df.plot(x='Date',y='Temp',style='k',ax=ax,label='Temp')

# 绘制二次多项式


# knn
ax.plot(df['Date'],df['KNN'],'g.',label='KNN')

ax.plot(df['Date'],df['随机森林'],'r.',label='随机森林')

#
ax.plot(df['Date'],df['线性回归'],'b.',label='线性回归')

plt.legend(fontsize=20,markerscale=5)
# 设置坐标文字大小
plt.tick_params(labelsize=25)
#
plt.grid()
#
plt.show()


df.to_csv('final_regression.csv',index=False)


result=pd.read_csv('final_regression.csv')

result.head()

result_analyse=result.describe().copy()

result_analyse

# 绘制
result_analyse.loc['MSE',:]=0

result_analyse

# 构造计算均方误差的函数
def MSE(yhat,y):
    error=np.array(yhat-y)
    error_power=np.power(error,2)
    MSE_error=np.sum(error_power)/len(y)
    return MSE_error

#
for each in result_analyse.columns:
    result_analyse.loc['MSE',each]=MSE(result[each],result['Temp'])

result_analyse

plt.figure(figsize=(20,20))
plt.subplot(421)
plt.title("平均值")
result_analyse.loc['mean',:].plot(kind="bar",color='k')
plt.subplot(422)
plt.title('方差')
result_analyse.loc['std':].plot(kind='bar',color='y')
plt.subplot(423)
plt.title('最小值')
result_analyse.loc['min',:].plot(kind="bar",color='m')
plt.subplot(424)
plt.title('下四分位数')
result_analyse.loc[ '25%',:].plot(kind='bar',color='c')
plt.subplot(425)
plt.title('中位数')
result_analyse.loc['50%',:].plot(kind='bar',color='r')
plt.subplot(425)
plt.title('上四分位数')
result_analyse.loc['75%',:].plot(kind='bar',color='g')
plt.subplot(427)
plt.title('最大值')
result_analyse.loc['max',:].plot(kind='bar',color='b')
plt.subplot(423)
plt.title("均方误差")
result_analyse.loc['MSE':].plot(kind='bar',color='deepskyblue')
plt.subplots_adjust(wspace=0.07,hspace=0.6) #训整子图间距
plt.show()


import numpy as np
import pandas as pd
from datetime import timedelta,datetime

# 获取数据集最后一天的日期
last_date=df2['Date'].max()
# 获取本地电脑当前时间
# last_date=datetime.now()
# 生成未来7天的日期
future_dates=pd.date_range(start=last_date+timedelta(days=1),periods=7)

#
future_df=pd.DataFrame({'Date':future_dates})

#
future_df['year']=future_df['Date'].apply(lambda x:x.year)
future_df['month']=future_df['Date'].apply(lambda x:x.month)
future_df['dow']=future_df['Date'].apply(lambda x:x.dayofweek)
future_df['dom']=future_df['Date'].apply(lambda x:x.day)

#
# 添加周末、上中下旬、四周等信息ر
future_df['weekend']= future_df['Date'].apply(lambda x: x.dayofweek>4)
future_df['weekend_sat']= future_df['Date'].apply(lambda x:x.dayofweek==5)
future_df['weekend_sun']=future_df['Date'].apply(lambda x: x.dayofweek==6)
future_df['half_month']= future_df['dom'].apply(lambda x:1 if x in range(1,16) else 2)
future_df['three_part_month']= future_df['dom'].apply(lambda x:1 if x in range(1, 11) else (2 if x in range(11, 21) else 3))
future_df['four_week_month']= future_df['dom'].apply(lambda x:1 if x in range(1,8) else (2 if x in range(8, 15) else (3 if x in range (15, 22) else 4)))
future_df['festival']=0

# 处理独热编码
columns_to_encoding = ['year', 'month','dow', 'dom','three_part_month','four_week_month']
future_df_encoded=pd.get_dummies(future_df, columns=columns_to_encoding)

# 确保未来数据与模型训练的数据结构一致
missing_cols= set(X_dummy.columns)-set(future_df_encoded.columns)
for col in missing_cols:
    future_df_encoded[col]=0

future_df_encoded= future_df_encoded[X_dummy.columns]
# 便用二次多项式特征处理器构造未来7天的二次特征
X_future_poly=poly_reg.transform(future_df_encoded)
# 使用训练好的二次多项式回归棉型进行预测
future_predictions = lin_reg_2.predict(X_future_poly)

# 将预测结果和未来日期关联
future_df['Predicted Temp']= future_predictions

# 显示未来7天的预测结果
print(future_df[['Date','Predicted Temp']])

# 绘制预测气温曲线
plt.figure(figsize=(10,6))
plt.plot(future_df['Date'], future_df['Predicted Temp'], 'bo-', label='Predicted Temperature (Next 7 Days)')
plt.title('Predicted Temperature for the Next 7 Days', fontsize=15)
plt.xlabel('Date', fontsize=12)
plt.ylabel('Temperature (℃)', fontsize=12)
plt.xticks(rotation=45)
plt.grid(True)
plt.legend()
plt.show()